home *** CD-ROM | disk | FTP | other *** search
- /********************************************************/
- /* TVSats Module for SkyView */
- /* */
- /* (c)1992 N P Hawkes */
- /* */
- /* Displays geostationary TV satellites */
- /********************************************************/
-
- #include "menu.h"
- #include "dbox.h"
- #include "bbc.h"
- #include "wimpt.h"
- #include "dbox.h"
- #include "sprite.h"
- #include "res.h"
- #include "resspr.h"
- #include "werr.h"
-
- #include "sv_header.h"
- #include "tvsats.h"
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <ctype.h>
-
- /********************************************************/
- /* Constants */
- /********************************************************/
- #define RHO 0.151 /* Ratio of Earth's radius*/
- /* to radius of geostat- */
- /* ionary orbit. */
- #define DISP_NAME "TV sats." /* Entry in Display menu. */
- #define SEL_NAME "TV sat." /* Entry in Select menu. */
-
- #define MAX_SATS 25 /* Max no. of satellites. */
- #define FILE_NAME "SatData" /* Name of data file. */
-
- #define FMT_LEN 256 /* Len. of format string. */
- #define NAME_LEN 15 /* Length of name field. */
- #define DESC_LEN 30 /* Max len. of decsription*/
-
- #define SPR_NAME "tvsat" /* Name of sprite. */
- #define SPR_X0 -12 /* Bounding box of */
- #define SPR_Y0 -12 /* sprite, OS units, */
- #define SPR_X1 14 /* relative to */
- #define SPR_Y1 14 /* plotting position. */
- #define SPR_COL 5 /* Sprite x offset. */
- #define SPR_ROW 4 /* Sprite y offset. */
- #define SPR_MODE MODE_20 /* Sprite mode. */
-
- /********************************************************/
- /* New types of variable. */
- /********************************************************/
- /* Structure describing one satellite. */
- typedef struct {
- char name[NAME_LEN+1]; /* Name of satellite. */
- REAL longit; /* Longitude of satellite. */
- char descr[DESC_LEN+1]; /* Description. */
- int horiz_id; /* id in Horiz window. */
- int vert_id; /* id in Vert window. */
- } satstr;
-
- /********************************************************/
- /* Global Variables */
- /********************************************************/
- static BOOL display_flag = FALSE; /* 'Enabled' flag. */
- static int moduleid; /* Module ID. */
-
- static FILE *fileptr; /* Ptr to data file. */
- static char fmt[FMT_LEN]; /* For format string.*/
- static satstr sat_data[MAX_SATS]; /* Main data store. */
- static int sat_count = 0; /* No. of satellites.*/
-
- static menu sat_menu; /* For selecting a satellite. */
-
- static double cos_anglimit = RHO;
- /* Satellite is below horizon if cos of angle between */
- /* vector to it and vector to observer is less than */
- /* cos_anglimit (where origin is centre of Earth). */
-
- static double delta; /* For diff between longitude of */
- /* observer & that of satellite. */
- static double dlatit; /* Double version of latitude of */
- /* observer. */
- static double cosbeta; /* For cosine of angle OCS, where*/
- /* O=observer, C=centre of earth,*/
- /* S=satellite. */
-
- static sprite_id spr_id; /* ID of satellite sprite. */
-
- /********************************************************/
- /* Function Prototypes */
- /********************************************************/
- static void tvsats_buildfn(void);
- static void tvsats_selectfn(selectfn_reasoncode reason);
- static BOOL tvsats_displayfn(BOOL *enabptr);
- static os_error *tvsats_plotfn(int x, int y, int id);
- static void tvsats_infofn(int id);
- static BOOL read_satdata(satstr *sptr);
- static char *trim(char *str);
- static void tvsat_altaz(int id, REAL *altptr, REAL *azimptr);
- static void read_optional(char *string, int count);
-
- /********************************************************/
- /* Initialisation Function */
- /********************************************************/
- BOOL tvsats_initfn(int moduleno, modulestr *tvsats)
- {
- int i;
- sprite_id nametype_id;
- os_error *errptr;
-
- /* Record the module number of this module. */
- moduleid = moduleno;
-
- /* Open data file. */
- fileptr = res_openfile(FILE_NAME, "r");
- if (fileptr==NULL) return FALSE;
-
- /* Construct the format string for reading the data. */
- sprintf(fmt, "%%%ic%%f %%c", NAME_LEN);
-
- /* Read data, one satellite at a time. Stop on first */
- /* error (probably EOF). Stay within array bounds. */
- while (sat_count < MAX_SATS && \
- read_satdata(&sat_data[sat_count]))
- sat_count++;
-
- /* Close file. Fatal error if it won't close. */
- if (fclose(fileptr) != 0)
- werr(FATAL, "TVSats Error: Can't close Data file");
-
- /* Quit if no items have been read. */
- if (sat_count == 0) return FALSE;
-
- /* Build menu for Select function. */
- /* Use menu_new for first item, menu_extend thereafter. */
- sat_menu = menu_new(SEL_NAME ":", sat_data[0].name);
- if (sat_menu == NULL) return FALSE;
- for (i=1; i<sat_count; i++)
- menu_extend(sat_menu, sat_data[i].name);
-
- /* Fill in the fields of the modulestr. */
- tvsats->buildfn = tvsats_buildfn;
- tvsats->selectfn = tvsats_selectfn;
- tvsats->dispfn = tvsats_displayfn;
- tvsats->infofn = tvsats_infofn;
- tvsats->initial = display_flag;
- tvsats->display_entry = DISP_NAME;
- tvsats->display_menu = NULL;
- tvsats->select_entry = SEL_NAME;
- tvsats->select_menu = sat_menu;
-
- /* Set up the sprite_id structure which identifies the */
- /* satellite sprite. */
- /* First set up a name-type identifier. */
- nametype_id.s.name = SPR_NAME;
- nametype_id.tag = sprite_id_name;
- /* Then get the address of the sprite, and put it in */
- /* the global sprite identifier spr_id. */
- errptr = sprite_select_rp(resspr_area(), &nametype_id, &spr_id.s.addr);
- if (errptr != NULL) return FALSE;
- /* Finally tag the identifier spr_id as address-type. */
- spr_id.tag = sprite_id_addr;
-
- return TRUE;
- }
-
- /*------------------------------------------------------*/
- /* Function to read in a line of satellite data. */
- /* Name, longitude and E/W designator must be present. */
- /* Description is optional. */
- /* Return TRUE if at least the minimum data have been */
- /* sucessfully read, FALSE otherwise. */
- /*------------------------------------------------------*/
- static BOOL read_satdata(satstr *sptr)
- {
- /* Temp storage for sat's longitude (in float form): */
- float flongit;
- /* Temp storage for char which designates E or W: */
- char ew;
-
- /* Read name, longitude, and E/W. */
- /* Return FALSE if error (probably EOF) occurs. */
- if (fscanf(fileptr, fmt,
- sptr->name,
- &flongit,
- &ew)
- != 3)
- return FALSE;
-
- /* Put a terminating \0 into the name string. Then */
- /* trim trailing blanks. */
- sptr->name[NAME_LEN] = '\0';
- trim(sptr->name);
-
- /* Convert longit to radians. <0 if East. */
- if (ew == 'E' || ew == 'e') flongit = -flongit;
- sptr->longit = (REAL)flongit * CONV;
-
- /* Read description, if it is present. */
- /* Trim any trailing blanks. */
- read_optional(sptr->descr, DESC_LEN);
- trim(sptr->descr);
-
- return TRUE;
- }
-
- /*------------------------------------------------------*/
- /* Function which reads optional description string at */
- /* end of current line. Reads at most 'count' chars. */
- /* Returns null string if description is absent. */
- /*------------------------------------------------------*/
- static void read_optional(char *string, int count)
- {
- int c;
-
- /* Skip any leading white space (except '\n'). */
- do
- c = fgetc(fileptr);
- while (isspace(c) && c != '\n');
-
- /* Read characters into string until: */
- /* 'count' chars have been read in, */
- /* or \n is seen (in which case do not store \n), */
- /* or EOF is seen. */
- while (count>0 && c!='\n' && c!=EOF)
- {
- *string++ = c;
- count--;
- c = fgetc(fileptr);
- }
-
- /* Add terminating \0. */
- *string = '\0';
-
- /* If neither \n or EOF was seen, discard remainder */
- /* of current line. */
- while (c!='\n' && c!=EOF) c = fgetc(fileptr);
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function which trims trailing blanks from a string. */
- /*------------------------------------------------------*/
- static char *trim(char *str)
- {
- char *ptr;
-
- for (ptr = str+strlen(str); ptr>str && *(ptr-1)==' '; ptr--)
- ;
- *ptr = '\0';
-
- return str;
- }
- /********************************************************/
- /* List-Building Function */
- /********************************************************/
- static void tvsats_buildfn(void)
- {
- int i;
- plotobj tvsat;
-
- /* Bounding box of plotting symbol, relative to */
- /* position of symbol: */
- static wimp_box size = {SPR_X0, SPR_Y0, SPR_X1, SPR_Y1};
-
- /* For each satellite in turn: */
- for (i=0; i<sat_count; i++)
- {
-
- /* Calculate cosine of angle OCS (Observer, Centre */
- /* of earth, Satellite). */
- delta = (double)ob_data.longit - (double)sat_data[i].longit;
- dlatit= (double)ob_data.latit;
- cosbeta = cos(dlatit)*cos(delta);
- if (cosbeta > 1.0) cosbeta = 1.0;
- if (cosbeta < -1.0) cosbeta = -1.0;
-
- /* See if satellite is below the horizon, by */
- /* comparing cosbeta with limit. */
- if (cosbeta < cos_anglimit)
- {
- /* Do not bother to offer this one to main program*/
- /* Just set horiz and vert ids to NOWHERE, and */
- /* continue with next satellite. */
- sat_data[i].horiz_id = NOWHERE;
- sat_data[i].vert_id = NOWHERE;
- continue;
- }
-
- /* Build plotobj. */
- tvsat.id = i;
- tvsat.module = moduleid;
- tvsat.plotfn = tvsats_plotfn;
- tvsat_altaz(i, &tvsat.alt, &tvsat.azim);
- tvsat.size = size;
-
- /* Offer this to the main program. */
- addobj(tvsat, &sat_data[i].horiz_id, &sat_data[i].vert_id);
-
- }
-
- return;
- }
-
- /*------------------------------------------------------*/
- /* Function to calculate alt & azim of satellite i. */
- /*------------------------------------------------------*/
- static void tvsat_altaz(int id, REAL *altptr, REAL *azimptr)
- {
- /* Assumes delta, dlatit and cosbeta are already valid */
- /* for this satellite. */
-
- double sinbeta;
- double cosalt, alt, cosazim, azim;
- static double epsilon = 8.7E-04;
-
- /* Special case when observer is almost directly */
- /* beneath satellite. */
- if (fabs(delta) < epsilon && fabs(dlatit) < epsilon)
- {
- *altptr = PIby2;
- *azimptr = (REAL)0.0;
- return;
- }
-
- sinbeta = sin(acos(cosbeta));
-
- cosalt = sinbeta/sqrt(1.0+RHO*RHO-2.0*RHO*cosbeta);
- if (cosalt > 1.0) cosalt = 1.0;
- if (cosalt < -1.0) cosalt = -1.0;
- cosazim = -tan(dlatit)*cosbeta/sinbeta;
- if (cosazim > 1.0) cosazim = 1.0;
- if (cosazim < -1.0) cosazim = -1.0;
-
- alt = acos(cosalt);
- azim = (delta >= 0 ? acos(cosazim): -acos(cosazim));
-
- *altptr = (REAL)alt;
- *azimptr= (azim >= 0 ? (REAL)azim: (REAL)2.0*PI + (REAL)azim);
-
- return;
- }
-
-
- /********************************************************/
- /* Object-Selecting Function */
- /********************************************************/
- static void tvsats_selectfn(selectfn_reasoncode reason)
- {
- int menu_hit, sat_id;
- REAL sat_longit;
-
- switch (reason)
- {
- case new_selection:
- /* Look at list of menu hits to find which */
- /* satellite is to be selected. */
- menu_hit = module_submenu_hits[0];
-
- /* If no hits on Satellite menu, flag the failure */
- /* and return. Also return if hit is off the end.*/
- if (menu_hit <= 0 || menu_hit > sat_count)
- {
- selection.selected_OK = FALSE;
- return;
- }
-
- /* Fill in Selection details for requested */
- /* satellite. Allow for menu entries being */
- /* indexed from 1 instead of 0. */
- sat_id = menu_hit - 1;
- selection.id = sat_id;
- selection.selected_OK = TRUE;
- selection.horiz_id = sat_data[sat_id].horiz_id;
- selection.vert_id = sat_data[sat_id].vert_id;
- selection.now = selection.horiz_id != NOWHERE || \
- selection.vert_id != NOWHERE;
- selection.rising = FALSE;
- selection.setting = FALSE;
- selection.culminating = FALSE;
- break;
-
- case window_selection:
- /* Inspect id field to find out which satellite */
- /* is to be selected. */
- sat_id = selection.id;
- selection.horiz_id = sat_data[sat_id].horiz_id;
- selection.vert_id = sat_data[sat_id].vert_id;
- selection.now = selection.horiz_id != NOWHERE || \
- selection.vert_id != NOWHERE;
- selection.rising = FALSE;
- selection.setting = FALSE;
- selection.culminating = FALSE;
- break;
-
- case recalculate_data:
- /* Observer details have changed, and plotting */
- /* lists have been rebuilt. Update Selection data.*/
- sat_id = selection.id;
- selection.horiz_id = sat_data[sat_id].horiz_id;
- selection.vert_id = sat_data[sat_id].vert_id;
- selection.now = selection.horiz_id != NOWHERE || \
- selection.vert_id != NOWHERE;
- break;
-
- case timeonly_recalculate:
- /* As above, but only the time of day (and */
- /* possibly the direction of view - this is of no */
- /* interest) have changed. */
- sat_id = selection.id;
- selection.horiz_id = sat_data[sat_id].horiz_id;
- selection.vert_id = sat_data[sat_id].vert_id;
- break;
-
- case sel_info_request:
- /* Write info into text buffer. */
- sat_id = selection.id;
- sat_longit = sat_data[sat_id].longit/CONV;
- sprintf(infoptr,"%s%s%s%.1f%s%s%s%s%s",
- "TV Satellite (Geostationary)\n",
- sat_data[sat_id].name, "\n",
- fabs((double)sat_longit),"° ",
- (sat_longit>0? "W\n" : "E\n"),
- sat_data[sat_id].descr,"\n",
- (selection.now? "Always visible from here":
- "Never visible from here"));
- break;
-
- default:
- /* Unknown option. Do nothing. */
- break;
-
- }
-
- return;
- }
-
-
- /********************************************************/
- /* Display Function */
- /********************************************************/
- static BOOL tvsats_displayfn(BOOL *enabptr)
- {
- /* Toggle Enable/Disable flag. */
- display_flag = !display_flag;
-
- /* Inform main program of new status. */
- *enabptr = display_flag;
-
- /* Windows will always need updating. */
- return TRUE;
- }
-
-
- /********************************************************/
- /* Plotting Function */
- /********************************************************/
- static os_error *tvsats_plotfn(int x, int y, int id)
- {
- return sv_plotsprite(&spr_id, SPR_MODE, x, y, SPR_COL, SPR_ROW);
- }
-
-
- /********************************************************/
- /* Info Function */
- /********************************************************/
- static void tvsats_infofn(int id)
- {
- REAL longit = sat_data[id].longit/CONV;
-
- sprintf(infoptr,"%s%s%s%.1f%s%s%s",
- "TV Satellite (Geostationary)\n",
- sat_data[id].name, "\n",
- fabs((double)longit),"° ",
- (longit>0? "W\n" : "E\n"),
- sat_data[id].descr);
-
- return;
- }
-